/**
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Autogenerated file -- DO NOT EDIT!

<%
require 'yaml'

def get_type(type)
  @type_map ||= {
    'u1' => 'DataType::BOOL',
    'i8' => 'DataType::INT8',
    'i16' => 'DataType::INT16',
    'i32' => 'DataType::INT32',
    'i64' => 'DataType::INT64',
    'u8' => 'DataType::UINT8',
    'u16' => 'DataType::UINT16',
    'u32' => 'DataType::UINT32',
    'u64' => 'DataType::UINT64',
    'b32' => 'DataType::UINT32',
    'b64' => 'DataType::UINT64',
    'f32' => 'DataType::FLOAT32',
    'f64' => 'DataType::FLOAT64',
    'ref' => 'DataType::REFERENCE',
    'any' => 'DataType::ANY',
    'i8[]' => 'DataType::INT8',
    'i16[]' => 'DataType::INT16',
    'i32[]' => 'DataType::INT32',
    'i64[]' => 'DataType::INT64',
    'u8[]' => 'DataType::UINT8',
    'u16[]' => 'DataType::UINT16',
    'u32[]' => 'DataType::UINT32',
    'u64[]' => 'DataType::UINT64',
    'b32[]' => 'DataType::UINT32',
    'b64[]' => 'DataType::UINT64',
    'f32[]' => 'DataType::FLOAT32',
    'f64[]' => 'DataType::FLOAT64',
    'ref[]' => 'DataType::REFERENCE',
    'none' => 'DataType::VOID'}
  raise "Unknown type #{type}" if @type_map[type].nil?
  @type_map[type]
end

def get_cc(inst)
  return 'ConditionCode::CC_EQ' if inst.opcode.start_with? 'jeq'
  return 'ConditionCode::CC_NE' if inst.opcode.start_with? 'jne'
  return 'ConditionCode::CC_LT' if inst.opcode.start_with? 'jlt'
  return 'ConditionCode::CC_GT' if inst.opcode.start_with? 'jgt'
  return 'ConditionCode::CC_LE' if inst.opcode.start_with? 'jle'
  return 'ConditionCode::CC_GE' if inst.opcode.start_with? 'jge'
  raise 'get_cc: wrong opcode #{inst.opcode}'
end

%>

#include "abckit_intrinsics.inl"

void ark::compiler::AbcKitInstBuilder::BuildDefaultAbcKitIntrinsic(const BytecodeInstruction *bcInst, RuntimeInterface::IntrinsicId intrinsicId)
{
    auto pc = GetPc(bcInst->GetAddress());
    ASSERT(!IsAbcKitInitObject(intrinsicId) && !IsAbcKitLoadObject(intrinsicId) && !IsAbcKitStoreObject(intrinsicId) &&
           !IsAbcKitLoadStatic(intrinsicId) && !IsAbcKitStoreStatic(intrinsicId) && !IsAbcKitLoadArray(intrinsicId) && !IsAbcKitStoreArray(intrinsicId));
    switch (intrinsicId) {
%   inst = nil
% Compiler::intrinsics.select {|intrinsic| intrinsic.space == "abckit" }.each do |intrinsic|
        case ark::compiler::RuntimeInterface::IntrinsicId::<%= intrinsic.entrypoint_name %>: {
%   Panda::instructions.each do |asm_ins|
%     if (asm_ins.mnemonic == intrinsic.method_name)
%       inst = asm_ins
%     end
%   end
%   if (inst)
%     format = "BytecodeInst::Format::" + inst.format.pretty.upcase
%     acc_read = inst.acc.include?("in")
%     acc_write = inst.acc.include?("out")
%     ret_type = acc_write ? get_type(intrinsic.signature.ret) : "DataType::VOID"
%     params_arr = inst.operands
%     num_vregs = params_arr.select{|b| b.reg? && b.src?}.length
%     num_imms = params_arr.select{|b| b.imm?}.length
%     num_ids = params_arr.select{|b| b.id?}.length
%     num_inputs = acc_read ? num_vregs + 1 : num_vregs
            auto retType = ark::compiler::<%= get_type(intrinsic.signature.ret) %>;
            ark::compiler::IntrinsicInst *inst = GetGraph()->CreateInstIntrinsic(retType, pc, intrinsicId);
%     if (num_inputs != 0)
            size_t inputsCount = <%= num_inputs %>;
            inst->ReserveInputs(inputsCount);
            inst->AllocateInputTypes(GetGraph()->GetAllocator(), inputsCount);
%     end
%     if acc_read
            {
                auto input = GetDefinitionAcc();
                inst->AppendInput(input);
%       op = inst.acc_and_operands.select { |op| op.acc? && op.src? }.first
                inst->AddInputType(ark::compiler::<%= get_type(op.type) %>);
            }
%     end
%     imm_index = 0
%     vreg_index = 0
%     id16_index = 0
%     out_idx = nil
%     params_arr.each do |param|
%       if param.imm?
            auto imm<%= imm_index %> = static_cast<uint32_t>(bcInst->GetImm<<%= format %>, <%= imm_index %>>());
            inst->AddImm(GetGraph()->GetAllocator(), imm<%= imm_index %>);
%         imm_index = imm_index + 1
%       elsif param.reg?
%         if param.src?
            {
                auto input = GetDefinition(bcInst->GetVReg(<%= vreg_index %>));
                inst->AppendInput(input);
                inst->AddInputType(ark::compiler::<%= get_type(param.type) %>);
            }
%         else
%           out_idx = vreg_index
%         end
%         vreg_index = vreg_index + 1
%       elsif param.id?
%         if inst.properties.include?("string_id")
            uint32_t stringId<%= id16_index %> = bcInst->GetId(<%= id16_index %>).AsFileId().GetOffset();
            inst->AddImm(GetGraph()->GetAllocator(), stringId<%= id16_index %>);
%       elsif inst.properties.include?("literalarray_id")
            uint32_t literalarrayId<%= id16_index %> = bcInst->GetId(<%= id16_index %>).AsIndex();
            inst->AddImm(GetGraph()->GetAllocator(), literalarrayId<%= id16_index %>);
%       elsif inst.properties.include?("type_id")
            uint32_t typeId<%= id16_index %> = bcInst->GetId(<%= id16_index %>).AsIndex();
            typeId<%= id16_index %> = GetRuntime()->ResolveTypeIndex(GetGraph()->GetMethod(), typeId<%= id16_index %>);
            inst->AddImm(GetGraph()->GetAllocator(), typeId<%= id16_index %>);
%       elsif inst.properties.include?("method_id")
            uint32_t mId<%= id16_index %> = bcInst->GetId(<%= id16_index %>).AsIndex();
            mId<%= id16_index %> = GetRuntime()->ResolveMethodIndex(GetGraph()->GetMethod(), mId<%= id16_index %>);
            inst->AddImm(GetGraph()->GetAllocator(), mId<%= id16_index %>);
%         end
%         id16_index = id16_index + 1
%       end
%     end
            auto method = GetGraph()->GetMethod();
            inst->SetMethod(method);
            AddInstruction(inst);
%     if acc_write
            UpdateDefinitionAcc(inst);
%     end
%     if out_idx
            UpdateDefinition(bcInst->GetVReg(<%= out_idx %>), inst);
%     end
%   end
            return;
        }
% end
        default:
            return;
    }
}

constexpr ark::compiler::Register MAX_NUM_SHORT_CALL_ARGS = 2;
constexpr ark::compiler::Register MAX_NUM_NON_RANGE_ARGS = 4;

void ark::compiler::AbcKitInstBuilder::BuildAbcKitInitObjectIntrinsic(const BytecodeInstruction *bcInst, bool isRange)
{
    auto methodId = GetRuntime()->ResolveMethodIndex(GetMethod(), bcInst->GetId(0).AsIndex());
    size_t argsCount = GetMethodArgumentsCount(methodId);
    ark::compiler::IntrinsicInst *inst {nullptr};
    if (argsCount > MAX_NUM_NON_RANGE_ARGS) {
        inst = GetGraph()->CreateInstIntrinsic(ark::compiler::DataType::REFERENCE, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_INIT_OBJECT_RANGE);
    } else if (argsCount > MAX_NUM_SHORT_CALL_ARGS) {
        inst = GetGraph()->CreateInstIntrinsic(ark::compiler::DataType::REFERENCE, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_INIT_OBJECT);
    } else {
        inst = GetGraph()->CreateInstIntrinsic(ark::compiler::DataType::REFERENCE, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_INIT_OBJECT_SHORT);
    }
    inst->AddImm(GetGraph()->GetAllocator(), methodId);
    inst->AllocateInputTypes(GetGraph()->GetAllocator(), argsCount);
    if (isRange) {
        auto startReg = bcInst->GetVReg(0);
        for (size_t i = 0; i < argsCount; startReg++, i++) {
            inst->AppendInput(GetDefinition(startReg));
            inst->AddInputType(GetRuntime()->GetMethodArgumentType(GetMethod(), methodId, i));
        }
    } else {
        for (size_t i = 0; i < argsCount; i++) {
            inst->AppendInput(GetDefinition(bcInst->GetVReg(i)));
            inst->AddInputType(GetRuntime()->GetMethodArgumentType(GetMethod(), methodId, i));
        }
    }
    auto method = GetGraph()->GetMethod();
    inst->SetMethod(method);
    AddInstruction(inst);
    UpdateDefinitionAcc(inst);
}

template<bool IS_ACC_WRITE>
void ark::compiler::AbcKitInstBuilder::BuildAbcKitLoadObjectIntrinsic(const BytecodeInstruction *bcInst, ark::compiler::DataType::Type rawRetType)
{
    auto fieldId = GetRuntime()->ResolveFieldIndex(GetMethod(), bcInst->GetId(0).AsIndex());
    auto retType = rawRetType;
    if (rawRetType != ark::compiler::DataType::REFERENCE) {
        retType = GetRuntime()->GetFieldTypeById(GetMethod(), fieldId);
    }
    ark::compiler::IntrinsicInst *inst {nullptr};
    switch (rawRetType) {
        case ark::compiler::DataType::UINT32: {
            inst = GetGraph()->CreateInstIntrinsic(retType, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_OBJECT);
            break;
        }
        case ark::compiler::DataType::UINT64: {
            inst = GetGraph()->CreateInstIntrinsic(retType, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_OBJECT_WIDE);
            break;
        }
        case ark::compiler::DataType::REFERENCE: {
            inst = GetGraph()->CreateInstIntrinsic(retType, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_OBJECT_OBJECT);
            break;
        }
        default:
            UNREACHABLE();
    }
    inst->AddImm(GetGraph()->GetAllocator(), fieldId);
    inst->AllocateInputTypes(GetGraph()->GetAllocator(), 1);
    inst->AppendInput(GetDefinition(bcInst->GetVReg(IS_ACC_WRITE ? 0 : 1)));
    inst->AddInputType(ark::compiler::DataType::REFERENCE);

    auto method = GetGraph()->GetMethod();
    inst->SetMethod(method);
    AddInstruction(inst);
    if constexpr (IS_ACC_WRITE) {
        UpdateDefinitionAcc(inst);
    } else {
        UpdateDefinition(bcInst->GetVReg(0), inst);
    }
}

template<bool IS_ACC_READ>
void ark::compiler::AbcKitInstBuilder::BuildAbcKitStoreObjectIntrinsic(const BytecodeInstruction *bcInst, ark::compiler::DataType::Type rawType)
{
    auto fieldId = GetRuntime()->ResolveFieldIndex(GetMethod(), bcInst->GetId(0).AsIndex());
    auto type = rawType;
    if (rawType != ark::compiler::DataType::REFERENCE) {
        type = GetRuntime()->GetFieldTypeById(GetMethod(), fieldId);
    }
    ark::compiler::IntrinsicInst *inst {nullptr};
    switch (rawType) {
        case ark::compiler::DataType::UINT32: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_STORE_OBJECT);
            break;
        }
        case ark::compiler::DataType::UINT64: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_STORE_OBJECT_WIDE);
            break;
        }
        case ark::compiler::DataType::REFERENCE: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_STORE_OBJECT_OBJECT);
            break;
        }
        default:
            UNREACHABLE();
    }

    inst->AddImm(GetGraph()->GetAllocator(), fieldId);
    inst->AllocateInputTypes(GetGraph()->GetAllocator(), 2);
    ark::compiler::Inst *storeVal = nullptr;
    if constexpr (IS_ACC_READ) {
        storeVal = GetDefinitionAcc();
    } else {
        storeVal = GetDefinition(bcInst->GetVReg(0));
    }
    inst->AppendInput(storeVal);
    inst->AddInputType(type);
    inst->AppendInput(GetDefinition(bcInst->GetVReg(IS_ACC_READ ? 0 : 1)));
    inst->AddInputType(ark::compiler::DataType::REFERENCE);

    auto method = GetGraph()->GetMethod();
    inst->SetMethod(method);
    AddInstruction(inst);
}

void ark::compiler::AbcKitInstBuilder::BuildAbcKitLoadStaticIntrinsic(const BytecodeInstruction *bcInst, ark::compiler::DataType::Type rawType)
{
    auto fieldId = GetRuntime()->ResolveFieldIndex(GetMethod(), bcInst->GetId(0).AsIndex());
    auto type = rawType;
    if (rawType != ark::compiler::DataType::REFERENCE) {
        type = GetRuntime()->GetFieldTypeById(GetMethod(), fieldId);
    }
    ark::compiler::IntrinsicInst *inst {nullptr};
    switch (rawType) {
        case ark::compiler::DataType::UINT32: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_STATIC);
            break;
        }
        case ark::compiler::DataType::UINT64: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_STATIC_WIDE);
            break;
        }
        case ark::compiler::DataType::REFERENCE: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_STATIC_OBJECT);
            break;
        }
        default:
            UNREACHABLE();
    }
    inst->AddImm(GetGraph()->GetAllocator(), fieldId);

    auto method = GetGraph()->GetMethod();
    inst->SetMethod(method);
    AddInstruction(inst);
    UpdateDefinitionAcc(inst);
}

void ark::compiler::AbcKitInstBuilder::BuildAbcKitStoreStaticIntrinsic(const BytecodeInstruction *bcInst, ark::compiler::DataType::Type rawType)
{
    auto fieldId = GetRuntime()->ResolveFieldIndex(GetMethod(), bcInst->GetId(0).AsIndex());
    auto type = rawType;
    if (rawType != ark::compiler::DataType::REFERENCE) {
        type = GetRuntime()->GetFieldTypeById(GetMethod(), fieldId);
    }
    ark::compiler::IntrinsicInst *inst {nullptr};
    switch (rawType) {
        case ark::compiler::DataType::UINT32: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_STORE_STATIC);
            break;
        }
        case ark::compiler::DataType::UINT64: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_STORE_STATIC_WIDE);
            break;
        }
        case ark::compiler::DataType::REFERENCE: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_STORE_STATIC_OBJECT);
            break;
        }
        default:
            UNREACHABLE();
    }
    inst->AddImm(GetGraph()->GetAllocator(), fieldId);
    inst->AllocateInputTypes(GetGraph()->GetAllocator(), 1);
    inst->AppendInput(GetDefinitionAcc());
    inst->AddInputType(type);

    auto method = GetGraph()->GetMethod();
    inst->SetMethod(method);
    AddInstruction(inst);
}

void ark::compiler::AbcKitInstBuilder::BuildAbcKitLoadArrayIntrinsic(const BytecodeInstruction *bcInst, ark::compiler::DataType::Type type)
{
    ark::compiler::IntrinsicInst *inst {nullptr};
    switch (type) {
        case ark::compiler::DataType::UINT8:
        case ark::compiler::DataType::INT8:
        case ark::compiler::DataType::UINT16:
        case ark::compiler::DataType::INT16:
        case ark::compiler::DataType::UINT32:
        case ark::compiler::DataType::INT32:
        case ark::compiler::DataType::FLOAT32: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_ARRAY);
            break;
        }
        case ark::compiler::DataType::UINT64:
        case ark::compiler::DataType::INT64:
        case ark::compiler::DataType::FLOAT64: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_ARRAY_WIDE);
            break;
        }
        case ark::compiler::DataType::REFERENCE: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_LOAD_ARRAY_OBJECT);
            break;
        }
        default:
            UNREACHABLE();
    }
    inst->AllocateInputTypes(GetGraph()->GetAllocator(), 2);
    inst->AppendInput(GetDefinitionAcc());
    inst->AddInputType(ark::compiler::DataType::INT32);
    inst->AppendInput(GetDefinition(bcInst->GetVReg(0)));
    inst->AddInputType(ark::compiler::DataType::REFERENCE);

    auto method = GetGraph()->GetMethod();
    inst->SetMethod(method);
    AddInstruction(inst);
    UpdateDefinitionAcc(inst);
}

void ark::compiler::AbcKitInstBuilder::BuildAbcKitStoreArrayIntrinsic(const BytecodeInstruction *bcInst, ark::compiler::DataType::Type type)
{
    ark::compiler::IntrinsicInst *inst {nullptr};
    switch (type) {
        case ark::compiler::DataType::UINT8:
        case ark::compiler::DataType::INT8:
        case ark::compiler::DataType::UINT16:
        case ark::compiler::DataType::INT16:
        case ark::compiler::DataType::UINT32:
        case ark::compiler::DataType::INT32:
        case ark::compiler::DataType::FLOAT32: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_STORE_ARRAY);
            break;
        }
        case ark::compiler::DataType::UINT64:
        case ark::compiler::DataType::INT64:
        case ark::compiler::DataType::FLOAT64: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_STORE_ARRAY_WIDE);
            break;
        }
        case ark::compiler::DataType::REFERENCE: {
            inst = GetGraph()->CreateInstIntrinsic(type, GetPc(bcInst->GetAddress()), ark::compiler::RuntimeInterface::IntrinsicId::INTRINSIC_ABCKIT_STORE_ARRAY_OBJECT);
            break;
        }
        default:
            UNREACHABLE();
    }
    inst->AllocateInputTypes(GetGraph()->GetAllocator(), 3);
    inst->AppendInput(GetDefinitionAcc());
    inst->AddInputType(type);
    inst->AppendInput(GetDefinition(bcInst->GetVReg(0)));
    inst->AddInputType(ark::compiler::DataType::REFERENCE);
    inst->AppendInput(GetDefinition(bcInst->GetVReg(1)));
    inst->AddInputType(ark::compiler::DataType::INT32);

    auto method = GetGraph()->GetMethod();
    inst->SetMethod(method);
    AddInstruction(inst);
}
